/***************************************************************************************************
 *Copyright(C),2010-2016,Sumscope
 *FileName	:  gbkmap.cpp
 *Author	:  scofined.qi
 *Version	:  1.0
 *Date		:  2015/12/22
 *Desc		:  //用于主要说明此程序文件完成的主要功能
 *Relation :
 *Others	:  //其他内容说明
 *Function :  //主要函数列表，每条记录应包含函数名及功能简要说明
 *History	:
 * //修改历史记录列表，每条修改记录应包含修改日期、修改者及修改内容简介
 ***************************************************************************************************/
#include "gbkmap.h"
namespace qb {
namespace base {

////////////////////////////////////////////////////////////////////////////////
CGbkMap::GbkArea::GbkArea(ushort p1, ushort p2, kGbkHanziType t, int num)
    : type(t),
      count(num),
      hiBottom(p1 & 0x00ff),
      hiTop(p2 & 0x00ff),
      lowLeft((p1 & 0xff00) >> 8),
      lowRight((p2 & 0xff00) >> 8) {
  has7f = hiTop > 0x7F && hiBottom < 0x7F;
}

bool CGbkMap::GbkArea::exist(uchar x, uchar y) {
  return x >= lowLeft && x <= lowRight && y >= hiBottom && y <= hiTop;
}
unsigned short CGbkMap::GbkArea::get(int i) {
  ushort x, y, h;
  h = hiTop - hiBottom + (has7f ? 0 : 1);
  y = hiBottom + i % h;
  if (has7f && y >= 0x7f) {
    y++;
  }
  x = lowLeft + i / h;
  ushort gbk = ((y & 0x00ff) << 8) | x;
  return gbk;
}

CGbkMap::CGbkMap() {
  m_areas[kGbkHanziTypeGbk1] = GbkArea(0xA1A1, 0xA9FE, kGbkHanziTypeGbk1, 717);
  m_areas[kGbkHanziTypeGbk2] = GbkArea(0xB0A1, 0xF7FE, kGbkHanziTypeGbk2,
                                       6763);  // D7,FA-FE 没有对应汉字
  m_areas[kGbkHanziTypeGbk3] = GbkArea(0x8140, 0xA0FE, kGbkHanziTypeGbk3, 6080);
  m_areas[kGbkHanziTypeGbk4] = GbkArea(0xAA40, 0xFEA0, kGbkHanziTypeGbk4, 8160);
  m_areas[kGbkHanziTypeGbk5] = GbkArea(0xA840, 0xA9A0, kGbkHanziTypeGbk5, 166);
  m_areas[kGbkHanziTypeUser1] =
      GbkArea(0xAAA1, 0xAFFE, kGbkHanziTypeUser1, 564);
  m_areas[kGbkHanziTypeUser2] =
      GbkArea(0xF8A1, 0xFEFE, kGbkHanziTypeUser2, 658);
  m_areas[kGbkHanziTypeUser3] =
      GbkArea(0xA140, 0xA7A0, kGbkHanziTypeUser3, 672);
}
bool CGbkMap::IsGbkCode(const unsigned char* gbk) {
  kGbkHanziType type = GetGbkType(gbk);
  return type == kGbkHanziTypeGbk2 || type == kGbkHanziTypeGbk3 ||
         type == kGbkHanziTypeGbk4 || type == kGbkHanziTypeGbk1 ||
         type == kGbkHanziTypeGbk5;
}
bool CGbkMap::IsHanzi(const unsigned char* gbk) {
  kGbkHanziType type = GetGbkType(gbk);
  return type == kGbkHanziTypeGbk2 || type == kGbkHanziTypeGbk3 ||
         type == kGbkHanziTypeGbk4;
}
kGbkHanziType CGbkMap::GetGbkType(const unsigned char* gbk) {
  uchar x = *gbk;
  uchar y = *(gbk + 1);
  if (y == 0x7F || y == 0xFF) return kGbkHanziTypeCount;
  for (int i = 0; i < kGbkHanziTypeCount; i++) {
    if (m_areas[i].exist(x, y)) return kGbkHanziType(i);
  }
  return kGbkHanziTypeCount;
}
int CGbkMap::GetCount() {
  int sum = 0;
  for (int i = 0; i < kGbkHanziTypeCount; i++) {
    sum += m_areas[i].count;
  }
  return sum;
}
BaseString CGbkMap::GetAreaString(kGbkHanziType type) {
  int count = GetHanziCount(type) * 2 + 2;
  char* buf = new char[count];
  memset(buf, 0, count);
  GetAreaString(type, buf, count);
  BaseString str = buf;
  delete[] buf;
  return str;
}
int CGbkMap::GetAreaString(kGbkHanziType type, char* buf, int count) {
  int num = m_areas[type].count * 2;
  if (buf == NULL || count < num + 2) return num + 2;

  count = m_areas[type].count;
  for (int i = 0; i < count; i++) {
    unsigned short s = GetHanzi(type, i);
    *((unsigned short*)&buf[i * 2]) = s;
  }
  return count * 2;
}
bool CGbkMap::IsGbkString(const char* buf, int len) {
  int alpha = 0;
  const unsigned char* str = (const unsigned char*)buf;
  int hanzi[kGbkHanziTypeCount + 1] = {0};
  for (int i = 0; i < len; i++) {
    if (str[i] < 127)
      alpha++;
    else {
      kGbkHanziType type = GetGbkType((const unsigned char*)(str + i));
      hanzi[type] = hanzi[type] + 1;
      i++;
    }
  }
  return hanzi[kGbkHanziTypeUser1] <= 0 && hanzi[kGbkHanziTypeUser2] <= 0 &&
         hanzi[kGbkHanziTypeUser3] <= 0 && hanzi[kGbkHanziTypeCount] <= 0;
}
bool CGbkMap::IsVisibleChar(unsigned char c) {
  // 只允许可见的ascii字符：从0x20(space)到0x7e(~)以及\t
  // (sp)  ~
  return (c >= 0x20 && c <= 0x7e) || c == '\t';
}
}  // namespace base
}  // namespace qb
